package com.espirit.smc.server;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.net.URL;
import java.security.ProtectionDomain;
import java.util.TimeZone;

import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.io.FileUtils;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.util.RolloverFileOutputStream;
import org.eclipse.jetty.util.component.FileNoticeLifeCycleListener;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
import org.eclipse.jetty.webapp.Configuration.ClassList;
import org.eclipse.jetty.webapp.WebAppContext;

public class ServerMain {

	private static final Integer DEFAULT_PORT = 9100;

	private Integer port;

	private org.eclipse.jetty.server.Server server;

	private Logger logger = Log.getRootLogger();

	private String workPath;

	public Integer getPort() {
		return port;
	}

	public void setPort(Integer port) {
		this.port = port;
	}

	public org.eclipse.jetty.server.Server getServer() {
		return server;
	}

	private void start() throws Exception {
		if (port == null) {
			port = DEFAULT_PORT;
		}
		System.out.println("服务器端口为:" + port);
		System.out.println("正在启动服务...");

		initServer();

		server.start();
		server.join();
	}

	private void stop() throws Exception {
		if (server == null) {
			System.err.print("当前服务并未运行...");
			return;
		}
		if (server.isRunning() || server.isStarted()) {
			System.out.println("正在停止服务...");
			server.stop();
		} else {
			System.err.print("当前服务并未运行...");
		}
	}

	private void initServer() throws IOException {
		System.setProperty("org.eclipse.jetty.LEVEL", "DEBUG");
		System.setProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.StdErrLog");
		// Configure the Server Thread Pool.
		QueuedThreadPool threadPool = new QueuedThreadPool();
		threadPool.setMinThreads(10);
		threadPool.setMaxThreads(200);
		threadPool.setIdleTimeout(60000);
		threadPool.setDetailedDump(false);

		// Setup Jetty Server instance
		server = new org.eclipse.jetty.server.Server(threadPool);

		// Add shared Scheduler instance
		ScheduledExecutorScheduler scheduler = new ScheduledExecutorScheduler();
		server.addBean(scheduler);
		
		 // add Class list.Enable parsing of jndi-related parts of web.xml and jetty-env.xml
		 ClassList classList = ClassList.setServerDefault(server);
		 // Enable JNDI
		 classList.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration",
		 "org.eclipse.jetty.plus.webapp.EnvConfiguration",
		 "org.eclipse.jetty.plus.webapp.PlusConfiguration");
		 // Enable Annotation Scanning
		 classList.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
		 "org.eclipse.jetty.annotations.AnnotationConfiguration");
		
		
		// Http Configuration.
		HttpConfiguration httpConfig = new HttpConfiguration();
		httpConfig.setSecureScheme("https");
		httpConfig.setSecurePort(8443);
		httpConfig.setOutputBufferSize(32768);
		httpConfig.setRequestHeaderSize(8192);
		httpConfig.setResponseHeaderSize(8192);
		httpConfig.setSendServerVersion(true);
		httpConfig.setSendDateHeader(true);
		httpConfig.setHeaderCacheSize(512);

		// Add a HTTP Connector.
		ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory(httpConfig));
		// ServerConnector connector = new ServerConnector(server);
		connector.setPort(port);
		connector.setIdleTimeout(30000);
		connector.setSoLingerTime(-1);
		server.setConnectors(new Connector[] { connector });

		// Mixin the Start FileNoticeLifeCycleListener
		server.addLifeCycleListener(new FileNoticeLifeCycleListener("./jetty.state"));

		ProtectionDomain protectionDomain = ServerMain.class.getProtectionDomain();
		URL location = protectionDomain.getCodeSource().getLocation();
		String webPath = location.toExternalForm();
		logger.info("load webPath={}", webPath);
		WebAppContext context = new WebAppContext();
		context.setWar(webPath);
		context.setContextPath("/");
		// 设置work dir,war包将解压到该目录，jsp编译后的文件也将放入其中。
		String currentDir = new File(location.getPath()).getParent();
		resetTempDirectory(context, currentDir);
		// context.setParentLoaderPriority(true);
		server.setHandler(context);

		// Configure stderr and stdout to a Jetty rollover log file
		File logDir = new File("./logs");
		if (!logDir.exists()) {
			logDir.mkdirs();
		}
		RolloverFileOutputStream fos = new RolloverFileOutputStream("./logs/yyyy_mm_dd.stderrout.log", false, 90, TimeZone.getDefault());
		String datedFilename = fos.getFilename();

		PrintStream serverLog = new PrintStream(fos);

		logger.info("Redirecting stderr/stdout to ", datedFilename);
		System.setErr(serverLog);
		System.setOut(serverLog);

		server.setStopAtShutdown(true);
		server.setStopTimeout(5000);
	}

	private void resetTempDirectory(WebAppContext context, String currentDir) {
		File workDir;
		if (workPath != null) {
			workDir = new File(workPath);
		} else {
			workDir = new File(currentDir, "work");
		}
		try {
			FileUtils.deleteDirectory(workDir);
		} catch (IOException e) {
			logger.warn("删除临时目录出错！", e);
		}
		context.setTempDirectory(workDir);
	}

	public static void main(String[] args) {

		Options options = new Options();
		options.addOption("start", false, "Start server.");
		options.addOption("stop", false, "stop server.");
		options.addOption("P", true, "Server port number.");
		CommandLineParser parser = new BasicParser();
		Integer port = null;
		ServerMain sm = new ServerMain();
		try {
			CommandLine cmd = parser.parse(options, args);
			if (cmd.hasOption('P')) {
				try {
					port = Integer.parseInt(cmd.getOptionValue('P'));
					sm.setPort(port);
				} catch (Exception e) {
					sm.setPort(DEFAULT_PORT);
					System.out.println("端口配置错误,将使用默认端口9100作为服务器端口。");
				}
			} else if (cmd.hasOption("stop")) {
				try {
					sm.stop();
				} catch (Exception e) {
					System.err.println("服务停止失败！");
					e.printStackTrace();
					System.exit(0);
				}
			} else {
				try {
					if (!cmd.hasOption('P')) {
						sm.setPort(DEFAULT_PORT);
					}
					sm.start();
				} catch (Exception e) {
					System.err.println("服务启动失败！");
					e.printStackTrace();
					System.exit(0);
				}
			}
		} catch (ParseException e) {
			System.err.println("命令格式错误！请按如下格式执行 jar [start/stop] server.jar [-P 8080]");
			System.exit(100);
		}
	}
}
